﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Foxit.PDF;
using Foxit.PDF.Imaging;
using Foxit.PDF.IO;
using Foxit.PDF.PageElements;
using Sustainalytics.Entities.RiskRatings;
using Sustainalytics.Reporting.Framework;

namespace Sustainalytics.RiskRatings.Reporting
{
    class RiskRating_CustomColumnChart : PageElement
    {
        public float Left { get; set; }
        public float Top { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }
        public double CompanyValue { get; set; }
        public string CompanyName { get; set; }
        public List<RiskRatingCluster> RiskRatingClusterList { get; set; }
        public List<RiskRatingDataPoint> ChartValues { get; set; }
        public IEnumerable<RiskRatingDataPoint> ChartValues2 { get; set; }
        public int UnmanagedRisk { get; set; }

        private Group Elements()
        {
            var elements = new Group();
            Dictionary<string, RiskRatingCluster> ClusterDict = RiskRatingClusterList.ToDictionary(x => x.Code);

            float verticalDotSize, horisontalDotSize, columnWidth, maxValueXAxis, maxValueYAxis;
            int maxValueX, maxValueY;
            maxValueX = ChartValues == null ? ChartValues2.Max(x => x.XValue) : Math.Max(ChartValues.Max(x => x.XValue), ChartValues2.Max(x => x.XValue));
            maxValueY = ChartValues == null ? ChartValues2.Max(x => x.YValue) : Math.Max(ChartValues.Max(x => x.YValue), ChartValues2.Max(x => x.YValue));
            maxValueXAxis = (float)ClusterDict["D"].UpperBound;
            if (maxValueX > maxValueXAxis)
            {
                maxValueXAxis = ((int)maxValueX / (float)ClusterDict["X"].UpperBound + 1) * (float)ClusterDict["X"].UpperBound;
            }
            var YAxisSteppingValue = (int)(maxValueY * 5 / 16);
            maxValueYAxis = ((int)maxValueY / YAxisSteppingValue + 1) * YAxisSteppingValue;
            verticalDotSize = (Height - 80) / maxValueYAxis;
            horisontalDotSize = (Width - 20) / maxValueXAxis;
            columnWidth = (Width - 20) / maxValueXAxis / 2 - 0.5f;
            Point chartRootPoint = new Point((int)Left + 20, (int)(Top + Height) - 70);
            double companyValueRounded = Math.Floor(CompanyValue);
            if (companyValueRounded == 0)
                companyValueRounded = 1;


            //the chart drawings
            if (ChartValues != null)
            {
                foreach (RiskRatingDataPoint dataPoint in ChartValues)
                {
                    RgbColor color = ReportHelper.RiskRatingTypesColors[RiskRatingTypes.Universe];
                    elements.Add(new Line(chartRootPoint.X + dataPoint.XValue * horisontalDotSize,
                                chartRootPoint.Y,
                                chartRootPoint.X + dataPoint.XValue * horisontalDotSize,
                                chartRootPoint.Y - dataPoint.YValue * verticalDotSize,
                                columnWidth, color));
                }
            }

            

            if (ChartValues2 != null && ChartValues2.Any())
            {
                float currentCompanyScoreHeight = 0;
                var currentCompanyPoint = ChartValues2.FirstOrDefault(i => i.XValue == companyValueRounded);
                if(currentCompanyPoint != null)
                    currentCompanyScoreHeight = currentCompanyPoint.YValue;
                // draw the arrow
                elements.Add(new Foxit.PDF.PageElements.Image(ImageData.GetImage(ReportHelper.GetFile("ArrowHead.PNG")),
                                                chartRootPoint.X + (float)companyValueRounded * horisontalDotSize - 3.5f,
                                                chartRootPoint.Y - currentCompanyScoreHeight * verticalDotSize - 8.5f,
                                                0.02f));

                elements.Add(new Line(chartRootPoint.X + (float)companyValueRounded * horisontalDotSize - 1,
                                chartRootPoint.Y - currentCompanyScoreHeight * verticalDotSize - 8,
                                chartRootPoint.X + (float)companyValueRounded * horisontalDotSize - 1,
                                Top + 5,
                                1.5f, RgbColor.DarkGray));

                // add the company name
                if (CompanyName.Length > 23)
                {
                    var shortCompanyName = CompanyName.Length > 50 ? (CompanyName.Substring(0, 47) + "...") : CompanyName;
                    elements.Add(new TextArea(shortCompanyName,
                                        chartRootPoint.X + (float)companyValueRounded * horisontalDotSize - 44,
                                        Top - 13,
                                        88,
                                        18, Fonts.RobotoBold, 7f, TextAlign.Center, RgbColor.Black));
                }
                else
                {
                    var nameWidth = Fonts.RobotoBold.GetTextWidth(CompanyName, 7);
                    elements.Add(new Label(CompanyName,
                                        chartRootPoint.X + (float)companyValueRounded * horisontalDotSize - nameWidth / 2,
                                        Top - 5,
                                        nameWidth,
                                        18, Fonts.RobotoBold, 7f, TextAlign.Center, RgbColor.Black));
                }

                foreach (RiskRatingDataPoint dataPoint in ChartValues2)
                {
                    RgbColor color = ReportHelper.RiskRatingTypesColors[RiskRatingTypes.SubIndustry];
                    if (dataPoint.XValue == companyValueRounded)
                    {
                        if (ChartValues == null)
                            color = RgbColor.Black;
                    }

                    elements.Add(new Line(chartRootPoint.X + dataPoint.XValue * horisontalDotSize - 1,
                                chartRootPoint.Y,
                                chartRootPoint.X + dataPoint.XValue * horisontalDotSize - 1,
                                chartRootPoint.Y - dataPoint.YValue * verticalDotSize,
                                columnWidth, color));
                }
            }

            // the chart axis
            elements.Add(new Line(chartRootPoint.X,
                        chartRootPoint.Y,
                        Left + Width,
                        chartRootPoint.Y,
                        1f, RgbColor.Black));

            for (int j = 1; j <= maxValueYAxis; j++)
            {
                if (j % YAxisSteppingValue == 0)
                {
                    elements.Add(new Line(chartRootPoint.X,
                            chartRootPoint.Y - j * verticalDotSize,
                            Left + Width,
                            chartRootPoint.Y - j * verticalDotSize,
                            0.5f, RgbColor.Black, LineStyle.Dots));

                    elements.Add(new Label(j.ToString() + "%",
                            chartRootPoint.X - 20,
                            chartRootPoint.Y - j * verticalDotSize - 5,
                            15,
                            7f, Fonts.RobotoRegular, 6f, TextAlign.Right, RgbColor.Black));
                }
            }

            for (int i = 0; i < maxValueXAxis; i++)
            {
                if (i % (maxValueXAxis == 100 ? 20 : 4) == 0)
                {
                    elements.Add(new Line(chartRootPoint.X + i * horisontalDotSize,
                            chartRootPoint.Y + 1,
                            chartRootPoint.X + i * horisontalDotSize,
                            chartRootPoint.Y + 5,
                            1, RgbColor.Gray));
                    elements.Add(new Label(i.ToString(),
                            chartRootPoint.X + i * horisontalDotSize - 5,
                            chartRootPoint.Y + 7,
                            10,
                            7f, Fonts.RobotoRegular, 6f, TextAlign.Center, RgbColor.Black));
                }
            }
            elements.Add(new Line(chartRootPoint.X + maxValueXAxis * horisontalDotSize,
                            chartRootPoint.Y + 1,
                            chartRootPoint.X + maxValueXAxis * horisontalDotSize,
                            chartRootPoint.Y + 5,
                            1, RgbColor.Gray));
            elements.Add(new Label(maxValueXAxis.ToString(),
                            chartRootPoint.X + maxValueXAxis * horisontalDotSize - 6,
                            chartRootPoint.Y + 7,
                            15,
                            7f, Fonts.RobotoRegular, 6f, TextAlign.Left, RgbColor.Black));


            elements.Add(new Label(ClusterDict["X"].Assessment.ToString().Substring(0, 4),
                            chartRootPoint.X,
                            chartRootPoint.Y + 20,
                            (float)ClusterDict["X"].UpperBound * horisontalDotSize,
                            6f, Fonts.RobotoRegular, 5.5f, TextAlign.Center, RgbColor.Black));
            elements.Add(new Label(ClusterDict["A"].Assessment.ToString(),
                            chartRootPoint.X + (float)ClusterDict["A"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 20,
                            (float)(ClusterDict["A"].UpperBound - ClusterDict["A"].LowerBound) * horisontalDotSize,
                            6f, Fonts.RobotoRegular, 5.5f, TextAlign.Center, RgbColor.Black));
            elements.Add(new Label(ClusterDict["B"].Assessment.ToString(),
                            chartRootPoint.X + (float)ClusterDict["B"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 20,
                            (float)(ClusterDict["B"].UpperBound - ClusterDict["B"].LowerBound) * horisontalDotSize,
                            6f, Fonts.RobotoRegular, 5.5f, TextAlign.Center, RgbColor.Black));
            elements.Add(new Label(ClusterDict["C"].Assessment.ToString(),
                            chartRootPoint.X + (float)ClusterDict["C"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 20,
                            (float)(ClusterDict["C"].UpperBound - ClusterDict["C"].LowerBound) * horisontalDotSize,
                            6f, Fonts.RobotoRegular, 5.5f, TextAlign.Center, RgbColor.Black));
            elements.Add(new Label(ClusterDict["D"].Assessment.ToString(),
                            chartRootPoint.X + (float)ClusterDict["D"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 20,
                            (maxValueXAxis - (float)ClusterDict["D"].LowerBound) * horisontalDotSize,
                            6f, Fonts.RobotoRegular, 5.5f, TextAlign.Center, RgbColor.Black));

            elements.Add(new Line(chartRootPoint.X,
                            chartRootPoint.Y + 15,
                            chartRootPoint.X,
                            chartRootPoint.Y + 30,
                            0.5f, RgbColor.Black, LineStyle.DashSmall));
            elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["A"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 15,
                            chartRootPoint.X + (float)ClusterDict["A"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 30,
                            0.5f, RgbColor.Black, LineStyle.DashSmall));
            elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["B"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 15,
                            chartRootPoint.X + (float)ClusterDict["B"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 30,
                            0.5f, RgbColor.Black, LineStyle.DashSmall));
            elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["C"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 15,
                            chartRootPoint.X + (float)ClusterDict["C"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 30,
                            0.5f, RgbColor.Black, LineStyle.DashSmall));
            elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["D"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 15,
                            chartRootPoint.X + (float)ClusterDict["D"].LowerBound * horisontalDotSize,
                            chartRootPoint.Y + 30,
                            0.5f, RgbColor.Black, LineStyle.DashSmall));
            elements.Add(new Line(Left + Width,
                            chartRootPoint.Y + 15,
                            Left + Width,
                            chartRootPoint.Y + 30,
                            0.5f, RgbColor.Black, LineStyle.DashSmall));

            if (ChartValues != null)
            {
                var currentYOffset = chartRootPoint.Y + 32.5f;
                var BarHeight = 5;
                elements.Add(new Line(chartRootPoint.X,
                                currentYOffset,
                                chartRootPoint.X + (float)ClusterDict["A"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                BarHeight, new RgbColor(252, 238, 204)));
                elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["A"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                chartRootPoint.X + (float)ClusterDict["B"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                BarHeight, new RgbColor(249, 221, 153)));
                elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["B"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                chartRootPoint.X + (float)ClusterDict["C"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                BarHeight, new RgbColor(246, 205, 102)));
                elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["C"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                chartRootPoint.X + (float)ClusterDict["D"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                BarHeight, new RgbColor(243, 188, 51)));
                elements.Add(new Line(chartRootPoint.X + (float)ClusterDict["D"].LowerBound * horisontalDotSize,
                                currentYOffset,
                                Left + Width,
                                currentYOffset,
                                BarHeight, new RgbColor(240, 171, 0)));
            }
            return elements;
        }

        public override void Draw(PageWriter writer)
        {
            var elements = Elements();

            writer.Write_q_(true);
            elements.Draw(writer);
            writer.Write_Q(true);
        }
    }
}
